/*
* 实现一个栈结构 符合LIFO（先进后出）的原则，需要对插入数据和删除数据的功能进行限制
* 我们需要实现的方法：
*   push(eles):添加一个或者多个元素到栈顶
*   pop:移除栈顶的元素，同时返回被移除的元素
*   peek:返回栈顶的元素，不对栈本身做任何修改
*   isEmpty:判断栈里面是否为空，如果栈里面啥也没有，返回true，否则返回false
*   size:返回栈里面的元素个数，和数组的length属性类似
*   clear:移除栈里面的所有元素
*   for of接口:实现栈结构的迭代器接口
*
*
* */

class Stack{
    constructor(){
        this.count = 0 //栈的计数器
        this.items = {} //栈的数据仓库
    }
    push(...eles){ //添加一个值
        for(let i = 0,len = eles.length; i < len; i++){
            this.items[this.count] = eles[i] //采用计数器当前值（自然数）为下标key，存储实际数据
            this.count++ //每次push进一个数据，计数器自增1
        }
    }
    size(){ //返回栈的长度
        return this.count //每次查询的时候直接返回当前的计数器的值
    }
    isEmpty(){ //判断栈是否为空
        return !this.count //判断是否为空，直接返回计数器的取反，0取反为true，大于零取反为false
    }
    pop(){ //删除栈顶值并返回被删除的值
        if(this.isEmpty()){ //先进行判断，如果栈内为空，直接返回undefined
            return undefined
        }

        //如果不走上面的if判断则表明栈非空，那么就走下面的代码
        this.count-- //先进行计数器自减1，减去1之后得到的就是未删除前栈顶值的下标key，如果不明白，用几个数代入就知道了
        let result = this.items[this.count] //得到栈顶的值
        delete this.items[this.count] //删除栈顶的值
        return result //并返回被删除的栈顶的值
    }
    peek(){ //先进后出，返回栈顶的值不对栈做任何修改
        if(this.isEmpty()){ //先进行判断，如果栈内为空，直接返回undefined
            return undefined
        }
        return this.items[this.count - 1] //否则返回当前的栈顶值
    }
    clear(){ //清空栈内数据
        while(!this.isEmpty()){ //当栈内为非空则一直进行这个循环，pop删除直到栈内没有数据为止
            this.pop()
        }
    }
    toString(){ //转字符串
        if(this.isEmpty()){ //先进行判断，如果栈内为空，直接返回空字符串""
            return ""
        }
        let resultString = "" //如果非空则先用一个变量保存，因为我们也不知道有多少个值，默认为空字符串
        for(let i = 0; i < this.count; i++){
            resultString = `${resultString},${this.items[i]}` //如果无法理解，代入几个数进去即可明白
        }
        return resultString.slice(1) //因为上面的模板字符串拼接方式会在第一位返回多一个逗号，所以要用slice方法删除逗号
    }
    forEach(cb){ //forEach方法接收一个回调函数
        for(let i = 0; i < this.count; i++){
            cb(i,this.items[i],this) //回调函数接收三个参数index，items，arr本身
        }
    }
    [Symbol.iterator](){ //手动添加一个迭代器接口
        let self = this //先保存好当前的this
        let index = 0 //定义一个索引
        return {
            next(){
                if(index < self.count){ //如果没有遍历结束，则一个个返回当前值
                    return {
                        value:self.items[index++], //运用了闭包
                        done:false //false表示没有遍历完成
                    }
                }else{ //否则如果变量结束，则返回undefined
                    return {
                        value:undefined,
                        done:true //true表示遍历结束
                    }
                }
            }
        }
    }
}

let arr = new Stack()